﻿#include "Encrypt.h"

Encrypt* Encrypt::m_pInstance = NULL;
QMutex Encrypt::m_Mutex;

Encrypt::Encrypt(QObject *parent) :
    QObject(parent)
{
    m_aesKey.resize(16);
    m_aesIvec.resize(16);
}

QByteArray Encrypt::generateRandom(const int &size)
{
    QByteArray randomArray;
    for(int i=0; i<size; i++)
    {
        qsrand(QTime(0,0,0).secsTo(QTime::currentTime()) * qrand());
        char random = qrand()%255;
        randomArray.append(random);
    }
    return randomArray;
}

bool Encrypt::initRsaKey(const QString &path)
{
    FILE *fp = NULL;
    const char* keyParh = NULL;
    QByteArray array = path.toLatin1();
    keyParh = array.data();
    fp = fopen(keyParh,"r");

    if(fp == NULL)
    {
        qDebug()<<"Open publickey file failed!";
        fclose(fp);
        return false;
    }
    else
    {
        m_pRsaPublicKey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
        if(m_pRsaPublicKey == NULL)
        {
           qDebug()<<"Read publickey error!";
           ERR_print_errors_fp(stdout);
           fclose(fp);
           return false;
        }
    }
    fclose(fp);
    return true;
}


QByteArray Encrypt::rsaEncrypt(const QByteArray &data)
{

    if(data.size() == 0)
    {
        QByteArray encryptData;
        return encryptData;
    }

    char* strInput = NULL;
    char* strEncrypt = NULL;

    strInput  = (char *)data.data();
    strEncrypt = (char*)malloc(RSA_size(m_pRsaPublicKey));
    memset(strEncrypt,0,RSA_size(m_pRsaPublicKey));

    int reasult = RSA_public_encrypt(data.size(), (unsigned char*)strInput, (unsigned char*)strEncrypt, m_pRsaPublicKey, RSA_PKCS1_PADDING);

    if( reasult == -1)
    {
        qDebug()<<("RAS encrypt error");
        ERR_print_errors_fp(stdout);
    }

    QByteArray encryptData(strEncrypt,reasult);
    free(strEncrypt);
    return encryptData;
}


void Encrypt::setAesKey(const QByteArray &key, const QByteArray &ivec)
{
    m_aesKey = key;
    m_aesIvec = ivec;
}

void Encrypt::getAesKey(QByteArray &key, QByteArray &ivec)
{
    key = m_aesKey;
    ivec = m_aesIvec;
}


QByteArray Encrypt::mixAesKey(const QByteArray &clientKey, const QByteArray &serverKey)
{
    QByteArray reasult;
    for(int i=0; i<16; i++)
    {
        char a = clientKey.at(i);
        char b = serverKey.at(i);
        int sum = qAbs(a+b);
        char c = sum % 2 == 0 ? a ^ b : b ^ a;
        reasult.append(c);
    }
    return reasult;
}

QByteArray Encrypt::aesEncrypt(const QByteArray &data)
{
    if(data.size() == 0)
    {
        QByteArray encryptData;
        return encryptData;
    }

    quint32 len;
    unsigned char* strkey;
    unsigned char* strInput;
    unsigned char* strEncrypt;
    AES_KEY aes;


    strkey = (unsigned char *)m_aesKey.data();
    AES_set_encrypt_key(strkey, 128, &aes);

    if((data.size() + 1) % AES_BLOCK_SIZE == 0)
    {
       len=data.size() + 1;
    }
    else
    {
       len = ((data.size()+1)/AES_BLOCK_SIZE+1)*AES_BLOCK_SIZE;
    }

    char offset = len-data.size();
    QByteArray offsetData = data;
    for(int i=0; i<offset; i++)
    {
        offsetData.append(offset);
    }
//    qDebug()<<"EncryptData:"<<DataTypeConver::formatString(data);
    strInput = (unsigned char*)offsetData.data();

    strEncrypt = (unsigned char*)calloc(len, sizeof(unsigned char));

    QByteArray tempIvec = m_aesIvec;
    AES_cbc_encrypt(strInput, strEncrypt, len, &aes, (unsigned char*)tempIvec.data(), AES_ENCRYPT);


    QByteArray encryptData((char*)strEncrypt,len);
    free(strEncrypt);
    return encryptData;
}

QByteArray Encrypt::aesDecrypt(const QByteArray &data)
{
    if(data.size() == 0)
    {
        QByteArray decryptData;
        return decryptData;
    }

    quint32 len;
    unsigned char* strKey;
    unsigned char* strInput;
    unsigned char* strDecrypt;
    AES_KEY aes;

    strKey = (unsigned char *)m_aesKey.data();
    AES_set_decrypt_key(strKey, 128, &aes);

    strInput = (unsigned char*)data.data();
    len = data.size();
    strDecrypt = (unsigned char*)calloc(len, sizeof(unsigned char));

    QByteArray tempIvec = m_aesIvec;
    AES_cbc_encrypt(strInput, strDecrypt, len, &aes, (unsigned char*)tempIvec.data(), AES_DECRYPT);

    QByteArray decryptData((char*)strDecrypt,len);
    uchar last = (uchar)decryptData.at(decryptData.size()-1);
    decryptData.chop(last);
//    qDebug()<<"DecryptData:"<<DataTypeConver::formatString(decryptData);
    free(strDecrypt);
    return decryptData;

}

